Crackme7 by WiteG by ged_//tkm!

Cm ma level Hard, ale w porwnaniu z 9 (--Hard?!) to buka z marmolada. Crackmes jest zabezpieczony 3 algosami i 1 czysto teoretycznym problemem do rozkminienia.

Exek jest czym spakowany, ale tym si nie zajmujemy i robimy full dump w procdumpie.

Po wstpnych ogldzinach, wiemy ju, e..

:004022A2 loc_0_4022A2:                     ; CODE XREF: sub_0_40226A+2F j
:004022A2                 push    esi   ;name
:004022A3                 push    esi
:004022A4                 call    HASH_ALG1

Name jest hashowane. Algorytmy nazwaem ALG1..3, by moe s to jakie popularne algo. Z oglnie dostpnymi implementacjami, ale nie byem w stanie rozpozna adnego z nich. Troch teorii. Jakiekolwiek obliczenia dokonywane na name, s dla nas nieistotne - zawsze znamy name, wic w kadej chwili moemy wyripowa odp. prock, wklei do keygena i po sprawie.. Interesuj nas tylko przeksztacenia seriala, to wanie nimi trzeba si bdzie zaj przy pisaniu keygena.

:004022A9                 push    esi
:004022AA                 call    EXPAND_KEY_ALG1

Wszystkie EXPAND_KEY_ to procki 'rozszerzajce' dany klucz. Klucze s zazwyczaj krtkie, a co za tym idzie, maj nisk entropi (miar nie uporzdkowania). Chcc zwikszy entropi, autorzy korzystaj z jak najbardziej pojebanych funkcji, ktre w jaki sposb przeksztacaj nasz klucz, czynic go bardziej uytecznym kryptograficznie ;). Przykad: kto jako klucz podaje cig zerowych bajtw: 00000000 00000000. przypumy, e nasz algorytm szyfrujcy to zwyky xor. Co sie dzieje?

A XOR 00000000 = A
B XOR 00000000 = B

Czyli nie ma adnego szyfrowania :P. Jeli jednak przepucimy nasz klucz przez jak zamotan funkcj.. to dostaniemy cig o znacznie lepszych waciwociach, na przykad: d34af9c7 a1de770f. To jest jasne.. Idziemy dalej

:004022AF                 push    edi
:004022B0                 push    edi
:004022B1                 call    ALG1

Serial jest szyfrowany ALG1. Na razie nie zajmujemy si budow algosw.

:004022B6                 push    esi
:004022B7                 push    esi
:004022B8                 call    HASH_ALG1

Hash z name jest hashowany :)

:004022BD                 mov     ecx, 2
:004022C2                 mov     eax, esi
:004022C4                 mov     edx, edi
:004022C6
:004022C6 loc_0_4022C6:                     ; CODE XREF: sub_0_40226A+70 j
:004022C6                 push    eax
:004022C7                 call    EXPAND_KEY_ALG2
:004022CC                 push    edx
:004022CD                 push    edx
:004022CE                 call    ALG2
:004022D3                 add     eax, 10h        ; blok 128 bit
:004022D6                 add     edx, 10h
:004022D9                 dec     ecx
:004022DA                 jnz     short loc_0_4022C6

Hash jest rozszerzany, potem wynik z szyfrowania seriala przez ALG1, jest szyfrowany ALG2, czyli serial=ALG2(ALG1(serial))

:004022DC                 push    esi
:004022DD                 push    esi
:004022DE                 call    HASH_ALG1

hmm.. :P

:004022E3                 mov     ecx, 4
:004022E8                 mov     eax, esi
:004022EA                 mov     edx, edi
:004022EC
:004022EC loc_0_4022EC:                    ; CODE XREF: sub_0_40226A+96 j
:004022EC                 push    eax
:004022ED                 call    EXPAND_KEY_ALG3
:004022F2                 push    edx
:004022F3                 push    edx
:004022F4                 call    ALG3
:004022F9                 add     eax, 8          ; blok 64 bit
:004022FC                 add     edx, 8
:004022FF                 dec     ecx
:00402300                 jnz     short loc_0_4022EC

Chyba ju nie musz komentowa ;p. serial=ALG3(ALG2(ALG1(serial)))

:00402302
:00402302 loc_0_402302:                    ; CODE XREF: sub_0_40226A+A6 j
:00402302                 mov     eax, [edi+ecx*8]
:00402305                 inc     ecx
:00402306                 and     ecx, 3
:00402309                 jz      short loc_0_402312
:0040230B                 cmp     [edi+ecx*8], eax
:0040230E                 jbe     short loc_0_40236B
:00402310                 jmp     short loc_0_402302

I tutaj mamy ciekawy warunek, mianowicie 1 dword seriala ma by mniejszy od 3, 3 od 5, a 5 od 7, symbolicznie: 1<3<5<7. Nic ciekawego, ale wkrtce okae si, e to do uciliwe utrudnienie :P.

Teraz najtrudniejsza cze, so prosz o uwag ;)

Najpierw hashowany jest serial w formie w jakiej zosta wpisany w editboxa. Crackmes zaraz po konwersji ascii->hex robi sobie gdzie kopi i wanie ta kopia jest teraz hashowana (wczeniejsze szyfrowania byy dokonywane na innym buforze). Co sie teraz dzieje...

:0040232D            mov     ch, 2
:0040232F
:0040232F loc_0_40232F:
:0040232F            mov     cl, 4
:00402331            mov     eax, esi
:00402333            mov     edx, edi
:00402335
:00402335 loc_0_402335:
:00402335            push    edx         ;nasz zaszyfrowany serial
:00402336            call    feistel_init
:0040233B            push    eax
:0040233C            push    eax        ;hash z seriala !?!?
:0040233D            call    feistel_enc
:00402342            add     eax, 8     ;kolejne 8 bajtw hasha
:00402345            add     edx, 8     ;kolejne 8 bajtw klucza
:00402348            dec     cl         ;maa ptelka (szyfrujca)
:0040234A            jnz     short loc_0_402335
:0040234C            dec     ch         ;wiksza ptla (deszyfrujca)
:0040234E                 jnz     short loc_0_40232F

Nasz zaszyfrowany serial, ten ktry przeszed wszystkie mielenia:

serial=ALG3(ALG2(ALG1(serial)))

jest KLUCZEM do szyfrowania i pniejszego deszyfrowania, hasha z niezaszyfrowanego seriala (niech to bdzie HASH(editbox)), dlaczego pniejszego deszyfrowania? Bo wynik z feistel_enc, jest porwnywany z HASH(editbox) i jeli si nie zgadzaj to cya. hmm.. pewnie zamotaem ten opis :).

schemat:

1. licz HASH(editbox)
2. ustaw klucz dla feistel_enc. kluczem jest ALG3(ALG2(ALG1(serial)))
3. przepu HASH(editbox) przez feistel_enc
4. wynik znw przepu przez feistel_enc
5. jeli ostateczny wynik z punktu 4 jest rwny HASH(editbox), to OK

Pff.. nie potrafi janiej :P

I teraz caa magia, czyli jak policzy poprawny serial? zastanwmy si ;). Jeli zmienimy serial, to zmieni si te HASH(editbox) i cigle bdziemy mie sytuacje, w ktrej hash bdzie si zmienia, czyli dokonywanie jakichkolwiek oblicze na pojedynczym hashu nie ma sensu. Co nam pozostaje? Policzy uniwersalny serial, ktry najpierw bdzie szyfrowa, a potem deszyfrowa DOWOLNY hash. Jak dobrze, e biedronka jest tak blisko.

Wywnioskowalimy co naley zrobi, teraz trzeba to wprowadzi w ycie :P lookamy na feistel_init, funkcj rozszerzajc klucz..

seg000:00401D6D loc_0_401D6D:
seg000:00401D6D                 mov     [edi], eax
seg000:00401D6F                 rol     eax, 0Ch
seg000:00401D72                 mov     [edi+4], eax
seg000:00401D75                 rol     eax, 0Dh
seg000:00401D78                 add     edi, 8
seg000:00401D7B                 xchg    eax, ebx
seg000:00401D7C                 dec     ecx
seg000:00401D7D                 jnz     short loc_0_401D6D

Same role, nic ciekawego wic looknijmy do feistel_enc:

seg000:00401DA0                 mov     eax, edi
seg000:00401DA2                 xor     eax, [ecx]      ;A^key1

[...]
Tutaj jaka pojebana funkcja: f(A^key1)
key1 to pierwszy dword klucza btw ;)

seg000:00401DEC              mov     esi, offset lpBitsPos
seg000:00401DF1
seg000:00401DF1 loc_0_401DF1:
seg000:00401DF1              lodsb
seg000:00401DF2              bt      edx, eax        ; czy bit na pozycji
                                                     ; eax jest zapalony?
seg000:00401DF5              rcl     ebp, 1          ; CF=1 jeli tak
seg000:00401DF7              test    al, al
seg000:00401DF9              jnz     short loc_0_401DF1

Dodatkowe mieszanie bitw..

seg000:00401DFB                 xor     ebx, ebp

B = B XOR f(A^key1)

seg000:00401E00                 xchg    ebx, edi

Magiczny swap.. A staje sie B, B staje sie A

Czyli ukad Feistela. O ukadach Feistela i innych ciekawych rzeczach mona poczyta w "Block Ciphers And Cryptoanalysis" (Fauzan Mirza). Tutaj tylko podstawy. Powyszy algos dziaa mniej wicej tak:

A,B - 2 dwordy danych do szyfrowania
k1,k2 - 2 czesci klucza

B = B XOR f(A^k1)
A = A XOR f(B^k2)
zamie(A,B)
zapisz(A,B)

Jak to odwrci? Wystarczy poda dwordy klucza w odwrotnej kolejnoci!

wtedy zachodzi:

B = B XOR f(A^k2)  - musimy pamita, e A,B zostay zamienione miejscami
                     wic teraz, tak naprawd odszyfrowalimy A :)
A = A XOR f(B^k1)  - uwaga jak wyej
zamie(A,B)        - odpowiednie dwordy wracaj na swoje pozycje
zapisz(A,B)        - jest lo0zik ;)

Ok, algo rozszerzajce klucz skada si z samych roli, wic pierwsza myl, to klucz skadajcy si z samych 0! Ale nie moemy zapomnie o warunku 1<3<5<7 (look w gr), wic trzeba wymodzic jeszcze jakie wartoci.. FFFFFFFF FFFFFFFF samo nasuwa si na myl :). Ok, wic mamy wstpny format naszego uniwersalnego seriala:

00000000 00000000 xxxxxxxx xxxxxxxx
xxxxxxxx xxxxxxxx FFFFFFFF FFFFFFFF

Pozostao nam jeszcze wypeni jako te x :). Troch nad tym pokminilem i doszedem do wniosku, e dobrym rozwizaniem bd dwordy, w ktrych bity s na zmian zapalone i zgaszone, czyli 55555555 i AAAAAAAA. mamy ju cay serial:

00000000 00000000 55555555 AAAAAAAA
AAAAAAAA 55555555 FFFFFFFF FFFFFFFF

Dlaczego 55555555 AAAAAAAA??? Przedebuguj crackmesa to si dowiesz :P

I to ju waciwie koniec, teraz pozostaje ju tylko odszyfrowa ten bufor :P. Odwracanie poszczeglnych algosw jest nudne, so nie bd tego opisywa. Jak co to look do zaczonych srcw ;P

ged_//tkm!